// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/gpu/android/media_codec_video_decoder.h"

#include "base/logging.h"
#include "media/base/android/media_codec_util.h"
#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder_config.h"

namespace media {
namespace {

    // Don't use MediaCodec's internal software decoders when we have more secure
    // and up to date versions in the renderer process.
    bool IsMediaCodecSoftwareDecodingForbidden(const VideoDecoderConfig& config)
    {
        return !config.is_encrypted() && (config.codec() == kCodecVP8 || config.codec() == kCodecVP9);
    }

    bool ConfigSupported(const VideoDecoderConfig& config)
    {
        // Don't support larger than 4k because it won't perform well on many devices.
        const auto size = config.coded_size();
        if (size.width() > 3840 || size.height() > 2160)
            return false;

        // Only use MediaCodec for VP8 or VP9 if it's likely backed by hardware or if
        // the stream is encrypted.
        const auto codec = config.codec();
        if (IsMediaCodecSoftwareDecodingForbidden(config) && VideoCodecBridge::IsKnownUnaccelerated(codec, MEDIA_CODEC_DECODER)) {
            DVLOG(1) << "Config not supported: " << GetCodecName(codec)
                     << " is not hardware accelerated";
            return false;
        }

        switch (codec) {
        case kCodecVP8:
        case kCodecVP9: {
            if ((codec == kCodecVP8 && !MediaCodecUtil::IsVp8DecoderAvailable()) || (codec == kCodecVP9 && !MediaCodecUtil::IsVp9DecoderAvailable())) {
                return false;
            }

            // There's no fallback for encrypted content so we support all sizes.
            if (config.is_encrypted())
                return true;

            // Below 360p there's little to no power benefit to using MediaCodec over
            // libvpx so we prefer to use our newer version of libvpx, sandboxed in
            // the renderer.
            if (size.width() < 480 || size.height() < 360)
                return false;

            return true;
        }
        case kCodecH264:
            return true;
#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
        case kCodecHEVC:
            return true;
#endif
        default:
            return false;
        }
    }

} // namespace

MediaCodecVideoDecoder::MediaCodecVideoDecoder() { }

MediaCodecVideoDecoder::~MediaCodecVideoDecoder() { }

void MediaCodecVideoDecoder::Initialize(const VideoDecoderConfig& config,
    bool low_delay,
    CdmContext* cdm_context,
    const InitCB& init_cb,
    const OutputCB& output_cb)
{
    init_cb.Run(ConfigSupported(config));
}

void MediaCodecVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
    const DecodeCB& decode_cb)
{
    NOTIMPLEMENTED();
}

void MediaCodecVideoDecoder::Reset(const base::Closure& closure)
{
    NOTIMPLEMENTED();
}

std::string MediaCodecVideoDecoder::GetDisplayName() const
{
    return "MediaCodecVideoDecoder";
}

bool MediaCodecVideoDecoder::NeedsBitstreamConversion() const
{
    return true;
}

bool MediaCodecVideoDecoder::CanReadWithoutStalling() const
{
    NOTIMPLEMENTED();
    return false;
}

int MediaCodecVideoDecoder::GetMaxDecodeRequests() const
{
    return 4;
}

} // namespace media
